<?php
/*
xmlClasses

file version 2005-05-18 15:41:40
*/

class xmlClass {
/*--------------------------------------------------------------------------------------------------
constructeur
--------------------------------------------------------------------------------------------------*/
	//
	function xmlClass() {
		//echo "instanciation xmlclass";
		//$this->feeder=& new templateFeederMagic();
		// instanciation objet arraypath, données de travail internes
		//echo affvar($this->data);
		$this->dataPath=new arrayPath($this->data);
		//echo affvar($this->dataPath->get());
	}
/*--------------------------------------------------------------------------------------------------
methodes publiques
--------------------------------------------------------------------------------------------------*/
	// definies dans les classes héritées
/*--------------------------------------------------------------------------------------------------
proprietes
--------------------------------------------------------------------------------------------------*/
	var $views=array();
	var $queries=array();
	//var $data=array();
	//var $feeder; // objet templatefeedermagic
/*--------------------------------------------------------------------------------------------------
methodes privees
--------------------------------------------------------------------------------------------------*/

	/* renvoie un des modèles de vues nourri avec les données de travail
	*/
	/*function getFedView($id) {
		return $this->feeder->feed($this->views[$id],$this->data);
	}*/
	
	/* renvoie un résultat SQL
	*/
	/*function getSqlResult($id,$data=NULL) {
		// recup de la requete
		if (!isset($this->queries[$id]['sql']))
			return false;
		$query=$this->queries[$id]['sql'];
		//edition
		if ($data==NULL) $data=& $this->data;
		$query=$this->feeder->feed($query,$data);
		// execution
		$result=kapSqlResult($query);
		//echo affvar($result);
		return $result;
	}*/
	
	function getQuery($id) {
		if (!isset($this->queries[$id]['sql'])) return false;
		return $this->queries[$id]['sql'];/**/
		/*if (!isset($this->queries[$id])) return false;
		return $this->queries[$id];*/
	}
	
	function getView($id) {
		if (!isset($this->views[$id])) return false;
		return $this->views[$id];
	}
	
	function getData($path=NULL) {
		return $this->dataPath->get($path);
	}
	
	function setData($path,$value) {
		//if (is_array($value)) return false;
		return $this->dataPath->set($path,$value);
	}
}

class xmlClassBuilder {
/*--------------------------------------------------------------------------------------------------
constructeur
--------------------------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------------------------
methodes publiques
--------------------------------------------------------------------------------------------------*/
	/* builds class definition from xml class file
	and optional additional xml libraries files
	*/
	function buildClassFrom($xmlFile, $moreXmlFiles=array()) {
		// getting xpath doc from main file
		if (!$main=& $this->getxpathdoc($xmlFile)) {
			return false;
		}
		// extracting class name
		$this->classToBuild=$main->getContent("/xmlClass/@name");
		// building class declaration
		if (!$declaration=$this->makeDeclaration($main,$moreXmlFiles)) {
			return false;
		}
		/*echo "<pre>";
		print_r($declaration);
		echo "</pre>";/**/
		if (eval($declaration)===false) {
			// erreur de syntaxe dans la definition
			trigger_error("xmlClassBuilder->build: invalid class definition",E_USER_WARNING);
			echo "<pre>";
			print_r($declaration);
			echo "</pre>";
		}
		return true;
	}
	
	function & getInstanceFrom($xml, $moreXml=array()) {
		if (!$this->buildClassFrom($xml, $moreXml)) return false;
		$obj=new $this->classToBuild;
		return $obj;
	}

	/* construit la definition de classe, instancie et retourne l'objet
	*/
	function & build($xml, $moreXml=array()) {
		// import du xml, creation d'un objet xpath doc pour manipulation
		/*if (!$this->xpathDoc=new xpathdoc($xml)) {
			trigger_error("xmlClassBuilder->build: invalid xml");
			return false;
		}
		$this->xml=& $xml;
		// recup du nom de classe
		$this->classToBuild=$this->xpathDoc->getContent("/xmlClass/@name");
		
		// recup des definitions xml additionnelles (librairies de methodes)
		$args=func_get_args(); // recup des arguments
		// pour tous les arguments au dela du premier, copie dans moreXml
		for ($f=1; $f<count($args); $f++) {
			$this->moreXml[]=$args[$f];
		}
		
		// creation de la declaration de classe
		$definition=$this->makeDeclaration();
		if (eval($definition)===false) {
			// erreur de syntaxe dans la definition
			trigger_error("xmlClassBuilder->build: invalid class definition",E_USER_WARNING);
			echo "<pre>";
			print_r($definition);
			echo "</pre>";
		}// echo affvar($definition,'def',false);*/
		if (!$this->buildClassFrom($xml, $moreXml)) return false;
		$obj=new $this->classToBuild;
		//echo affvar($obj,'xmlclass object');
		return $obj;
	}
	/* returns instance of class
	*/
	
/*--------------------------------------------------------------------------------------------------
proprietes
--------------------------------------------------------------------------------------------------*/
	var $endLineChar="\n";
	var $classToBuild; // nom de la classe en cours de construction
	//var $moreXml=array(); // definitions XML additionnelles de méthodes
	// references to xpathdoc object, filename => object reference
	var $xpathdocs=array();
/*--------------------------------------------------------------------------------------------------
methodes privees
--------------------------------------------------------------------------------------------------*/
	/* creation de la declaration des methodes publiques
	*/
	function makePublicMethods(& $xpathDoc) {
		//trigger_error("making public methods");
		$def=$this->extractMethods($xpathDoc);
		//echo affvar($def,'public methods',false);
		return $def;
	}
	
	function makeProperties(& $xpathDoc) {
		$e=& $this->endLineChar;
		$prop="";
		/*."var \$xml='".str_replace("'","\'",$this->xpathDoc->getall())."';$e"*/;
		// vues
		$views=$xpathDoc->getAsTree("//views/view");
		//echo affvar($views);
		$prop.="var \$views=array(";
		foreach ($views as $view) {
			$prop.="'".$view['attributes()']['id']."'=>'".str_replace("'","\'",$view['text()'])."',";
		}
		$prop=substr($prop,0,-1).");$e"; // suppression dernière virgule superflue et fermeture du tableau 
		// requetes
		$queries=$xpathDoc->getAsTree("//sql/query");
		//echo affvar($views);
		$prop.="var \$queries=array(";
		foreach ($queries as $query) {
			$prop.="'".$query['attributes()']['id']."'=>array('sql'=>'".str_replace("'","\'",$query['text()'])."'),";
		}
		$prop=substr($prop,0,-1).");$e"; // suppression dernière virgule superflue et fermeture du tableau 
		// données de travail
		$prop.=$this->makeData($xpathDoc);
		return $prop;
	}

	/* etablit le tableau interne de données de travail par defaut de la classe
	*/
	function makeData(& $xpathDoc) {
		$e=& $this->endLineChar;
		$def="";
		// langage de définition
		$lang=$xpathDoc->getcontent("//data/@lang");
		switch ($lang) {
			case "php":
				$def.=$xpathDoc->getcontent("//data");
				break;
			default: trigger_error("xmlClassBuilder: unsupported @lang for &lt;data&gt; definition");
				break;
		}
		return $def;
	}
	// routine pour la fonction précédente
	/*function varFromXmlTree($tree) {
		echo affvar($tree,'tree',false);
		//switch ()
		return array(
			'key'=>'',
			'value'=>''
		);
	}*/
	
	/* ajout des methodes additionnelles
	( déclarées dans des fichiers additiionnels de routines/librairies)
	*/
	function makeMoreMethods($xmlFiles=array()) {
		$def='';
		foreach ($xmlFiles as $file) {
			$doc=& $this->getxpathdoc($file);
			$def.=$this->extractMethods($doc);
		}
		return $def;
	}
	/*
	main=xpath doc object, morefiles=xml libraries filenames
	*/
	function makeDeclaration(& $main, $morefiles=array()) {
		$e=& $this->endLineChar;
		//$class=$this->xpathDoc->getContent("/xmlClass/@name");
		$def="class ".$this->classToBuild." extends xmlClass \{$e"
		."/* public methods */$e"
		.$this->makePublicMethods($main)
		."/* properties */$e"
		.$this->makeProperties($main)
		."/* more (private) methods */$e"
		.$this->makeMoreMethods($morefiles)
		."}";
		//echo "<pre>".affvar($def,'definition',false)."</pre>";
		return $def;
	}
	
	/* extrait les methodes d'un objet xpathDoc (xml)
	et retourne une chaine de declarations
	*/
	function extractMethods(& $xpathDoc) {
		$e=& $this->endLineChar;
		$methods_list=$xpathDoc->getContentAsArray("//methods/method/@name");
		//echo affvar($methods);
		$def="";
		foreach ($methods_list as $m) {
			//echo affvar($m);
			$name=$m;
			if ($name==$this->classToBuild) {
				trigger_error("xmlClassBuilder: xml class can't overwrite constructors, a method has same name as the class",E_USER_WARNING);
				continue;
			}
			$parameters=$xpathDoc->getAsTree("//method[@name='$m']/parameter"); //echo affvar($parameters);
			$script=$xpathDoc->getContent("//method[@name='$m']/script");
			if (!$script) {
				// definition vide
				trigger_error("xmlClassBuilder: empty definition for method $name (tag &lt;script&gt;)",E_USER_NOTICE);
				continue;
				}
			$def.="function $name(";
			if (is_array($parameters)) {
				foreach ($parameters as $p) {
					$def.='$'.$p['attributes()']['name'];
					if (isset($p['attributes()']['default']))
						$def.='='.$p['attributes()']['default'];
					$def.=",";
				}
				$def=substr($def,0,-1); // suppression virgule superflue
			}
			$def.=") \{$e" //, fermeture des arguments
			.$script."$e}$e";
		}
		return $def;
	}
	
	/* creates and references xpathdoc objects from file to internal array
	or returns reference if object exists
	*/
	function & getXpathDoc($file) {
		if (!isset($this->xpathdocs[$file])) {
			if (!$xpathDoc=&new xpathDoc($file)) {
				return false;
			}
			$this->xpathdocs[$file]=& $xpathDoc;
		}
		return $this->xpathdocs[$file];
	}
}

/*--------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------*/
?>
